package org.jeik.data.dao;

import java.util.List;

import org.jeik.data.services.ServiceBase.Columns;
import org.jeik.utils.Log;

/**
 * 
 * @author AAsha
 *
 */
public abstract class QueryBuilder {
	
	public static final int STMT_SELECT = 1;
	public static final int STMT_UPDATE = 2;
	public static final int STMT_INSERT = 3;
	public static final int STMT_DELETE = 4;
	public static final int STMT_SLCT_WHERE  = 5;
	public static final int STMT_SELECT_COUNT = 6;
	
	/**
	 * Composes the SQL statements of types select, update, insert, delete, and where clauses
	 * 
	 * @param type type of statement
	 * @param tableName table name
	 * @param fields list of fields to get (select only)
	 * @param sets list of fields and values to set (update, insert)
	 * @param keys list of keys and values to match (select, update, delete)
	 */
	public static String createStatement(int type, String tableName, List<String> fields, List<String> keys) throws DataException {
		
		if (tableName != null) {
			//tableName = tableName.toUpperCase();
		}
		
		validateInputs(type, tableName, fields, keys);

		StringBuilder sb = new StringBuilder();
		
		switch (type) {
			case STMT_SELECT :
				sb.append("SELECT "); 
				addFieldsStatement(sb, fields);
				sb.append(" FROM "); 
				sb.append(tableName); 
				break;
			
			case STMT_SELECT_COUNT : 
				sb.append("SELECT COUNT(");
				addFieldsStatement(sb, fields);
				sb.append(") AS COUNT FROM ");
				sb.append(tableName);
				break;
			
			case STMT_UPDATE :
				sb.append("UPDATE "); 
				sb.append(tableName); 
				sb.append(" SET "); 
				for (String field:fields) {
					if(field.equals(Columns.ID.name())){
						continue;
					}
					sb.append(field);
					sb.append(" = "); 
					sb.append( "? , ");					
				}
				sb.delete(sb.length() - 2, sb.length());
				
				sb.append(" WHERE "); // SELECT * FROM table WHERE
				for (String key:keys) {
					sb.append(key);
					sb.append(" = ? ");
					sb.append(" AND "); 
				}
				sb.delete(sb.length() - 5, sb.length()); // SELECT * FROM table WHERE k1 = ?
				
				break;

			case STMT_INSERT :
				sb.append("INSERT INTO "); 
				sb.append(tableName); 
				sb.append(" (");
				
				StringBuffer valueTokens = new StringBuffer();	
				for (String field:fields) {
					sb.append(field);
					sb.append(", ");
					valueTokens.append("? , ");	
				}
				sb.delete(sb.length() - 2, sb.length());
				
				sb.append(") VALUES (");
				sb.append(valueTokens.toString());
				sb.delete(sb.length() - 2, sb.length());
				
				sb.append(")");
				break;

			case STMT_DELETE :
				sb.append("DELETE FROM "); 
				sb.append(tableName);
				break;
				
			case STMT_SLCT_WHERE :
				sb.append("SELECT "); 
				addFieldsStatement(sb, fields);
				sb.append(" FROM "); 
				sb.append(tableName); 
				sb.append(" WHERE "); // SELECT * FROM table WHERE
				for (String key:keys) {
					sb.append(key);
					sb.append(" = ? ");
					sb.append(" AND "); 
				}
				sb.delete(sb.length() - 5, sb.length()); // SELECT * FROM table WHERE k1 = ?
				break;

			default:
				throw new DataException("Undefined statement type " + type);

		}
		
		return sb.toString();
	}
	
	/**
	 * 
	 * @param type
	 * @param tableName
	 * @param sets
	 * @throws DataException
	 */
	private static void validateInputs(int type, String tableName, List<String> fields, List<String> keys) throws DataException {
		//   Validate table name here because all types of statements needs a table name except for STMT_WHERE
		if (type != STMT_SLCT_WHERE) {
			if (tableName == null || tableName.equals("")) {
				Log.error(QueryBuilder.class, "Table name connot be null or empty");
				throw new DataException("Table name connot be null or empty");
			}
		}else if(type == STMT_SLCT_WHERE){
			if (keys == null || keys.isEmpty()) {
				Log.error(QueryBuilder.class, "keys connot be null or empty");
				throw new DataException("keys connot be null or empty");
			}
		}
		
		//   Sets is required for update and insert statements. Cannot be null or empty
		if (type == STMT_UPDATE || type == STMT_INSERT) {
			if (fields == null || fields.isEmpty()) {
				Log.error(QueryBuilder.class, "fields connot be null or empty");
				throw new DataException("fields connot be null or empty");
			}
		}
	}
	
	/**
	 * Iterate over fields if exist and write them as in sql statement
	 * @param sb
	 * @param fields
	 */
	private static void addFieldsStatement(StringBuilder sb, List<String> fields){
		if (fields == null || fields.isEmpty()) {
			sb.append("*"); // SELECT *
		} else {
			for (String field:fields) {
			    sb.append(field);
				sb.append(", "); // SELECT f1,
			}
			sb.delete(sb.length() - 2, sb.length()); // SELECT f1
		}
	}
	
}
